<?php

namespace app\service;

use app\model\AccountingRecord;
use app\model\Room;
use app\model\User;

class SettlementStrategyService
{
    /**
     * 生成用户净结算策略
     * @param int $userId 用户ID
     * @param int $roomId 房间ID
     * @return array 净结算策略
     */
    public static function generateUserSettlementStrategy($userId, $roomId)
    {
        error_log("开始生成用户结算策略: user_id={$userId}, room_id={$roomId}");
        
        // 获取用户在房间中的所有 score 类型记录（和查看房间结算的计算方式一致）
        // 需要包括 user_id = $userId（用户支出的记录）和 target_user_id = $userId（用户收入的记录）
        $userRecords = AccountingRecord::where('room_id', $roomId)
            ->where(function($query) use ($userId) {
                $query->where('user_id', $userId)
                      ->orWhere('target_user_id', $userId);
            })
            ->where('type', 'score')
            ->get();

        error_log("用户记录数量: " . $userRecords->count());

        // 计算用户的总分数（和查看房间结算的计算方式一致）
        $totalScore = 0;
        foreach ($userRecords as $record) {
            if ($record->user_id == $userId) {
                // 用户主动记分给他人（支出，record->score已经是负数）
                $totalScore += $record->score;
            } elseif ($record->target_user_id == $userId) {
                // 他人记分给用户（收入，record->score是负数，减去负数等于加上正数）
                $totalScore -= $record->score;
            }
        }
        
        error_log("用户总分数（净分数）: {$totalScore}");
        
        // 如果没有 score 类型的记录，才不需要结算
        if ($userRecords->isEmpty()) {
            error_log("用户没有交易记录");
            return [
                'strategy' => 'no_records',
                'message' => '没有交易记录，无需结算',
                'transfers' => []
            ];
        }

        // 获取房间中所有用户的分数（和查看房间结算的计算方式一致）
        $allUserScores = self::getAllUserScores($roomId);
        
        if ($totalScore > 0) {
            // 用户是赢家，需要从输家那里收钱
            return self::generateWinnerStrategy($userId, $totalScore, $allUserScores);
        } elseif ($totalScore < 0) {
            // 用户是输家，需要给赢家钱
            return self::generateLoserStrategy($userId, abs($totalScore), $allUserScores);
        } else {
            // 用户分数为0，无需结算但需要记录
            error_log("用户分数为0，返回balanced策略");
            return [
                'strategy' => 'balanced',
                'message' => '您的分数为0，无需参与结算',
                'total_amount' => 0,
                'transfers' => []
            ];
        }
    }

    /**
     * 获取房间中所有用户的分数（和查看房间结算的计算方式一致）
     */
    private static function getAllUserScores($roomId)
    {
        $userScores = [];
        
        // 获取房间内所有用户
        $roomUsers = \app\model\RoomUser::where('room_id', $roomId)
            ->with('user')
            ->get();
        
        // 为每个用户计算净分数（和查看房间结算的计算方式一致）
        foreach ($roomUsers as $roomUser) {
            $userId = $roomUser->user_id;
            
            // 获取该用户的所有记录，只获取score类型的记录
            $records = AccountingRecord::where('room_id', $roomId)
                ->where(function($query) use ($userId) {
                    $query->where('user_id', $userId)
                          ->orWhere('target_user_id', $userId);
                })
                ->where('type', 'score')
                ->get();

            $userTotal = 0;
            foreach ($records as $record) {
                if ($record->user_id == $userId) {
                    // 用户主动记分给他人（支出，record->score已经是负数）
                    $userTotal += $record->score;
                } elseif ($record->target_user_id == $userId) {
                    // 他人记分给用户（收入，record->score是负数，减去负数等于加上正数）
                    $userTotal -= $record->score;
                }
            }
            
            $userScores[$userId] = $userTotal;
        }

        return $userScores;
    }

    /**
     * 生成赢家策略（从输家收钱）
     */
    private static function generateWinnerStrategy($userId, $winAmount, $allUserScores)
    {
        $transfers = [];
        $remainingAmount = $winAmount;
        
        // 按分数从低到高排序输家
        $losers = array_filter($allUserScores, function($score) {
            return $score < 0;
        });
        asort($losers);

        $loserNames = [];
        foreach ($losers as $loserId => $loseAmount) {
            if ($remainingAmount <= 0) break;
            
            $transferAmount = min(abs($loseAmount), $remainingAmount);
            
            if ($transferAmount > 0) {
                $loser = User::find($loserId);
                $winner = User::find($userId);
                
                $transfers[] = [
                    'from_user_id' => $loserId,
                    'from_username' => $loser ? $loser->nickname : '未知用户',
                    'to_user_id' => $userId,
                    'to_username' => $winner ? $winner->nickname : '未知用户',
                    'amount' => $transferAmount,
                    'description' => '最终净结算'
                ];
                
                $loserNames[] = ($loser ? $loser->nickname : '未知用户') . "({$transferAmount}分)";
                $remainingAmount -= $transferAmount;
            }
        }

        $loserList = implode('、', $loserNames);
        return [
            'strategy' => 'winner',
            'message' => "您需要从以下输家收取 {$winAmount} 分：{$loserList}",
            'total_amount' => $winAmount,
            'transfers' => $transfers
        ];
    }

    /**
     * 生成输家策略（给赢家钱）
     */
    private static function generateLoserStrategy($userId, $loseAmount, $allUserScores)
    {
        $transfers = [];
        $remainingAmount = $loseAmount;
        
        // 按分数从高到低排序赢家
        $winners = array_filter($allUserScores, function($score) {
            return $score > 0;
        });
        arsort($winners);

        $winnerNames = [];
        foreach ($winners as $winnerId => $winAmount) {
            if ($remainingAmount <= 0) break;
            
            $transferAmount = min($winAmount, $remainingAmount);
            
            if ($transferAmount > 0) {
                $winner = User::find($winnerId);
                $loser = User::find($userId);
                
                $transfers[] = [
                    'from_user_id' => $userId,
                    'from_username' => $loser ? $loser->nickname : '未知用户',
                    'to_user_id' => $winnerId,
                    'to_username' => $winner ? $winner->nickname : '未知用户',
                    'amount' => $transferAmount,
                    'description' => '最终净结算'
                ];
                
                $winnerNames[] = ($winner ? $winner->nickname : '未知用户') . "({$transferAmount}分)";
                $remainingAmount -= $transferAmount;
            }
        }

        $winnerList = implode('、', $winnerNames);
        return [
            'strategy' => 'loser',
            'message' => "您需要给以下赢家支付 {$loseAmount} 分：{$winnerList}",
            'total_amount' => $loseAmount,
            'transfers' => $transfers
        ];
    }

    /**
     * 生成房间整体净结算策略（最优匹配算法）
     */
    public static function generateRoomSettlementStrategy($roomId)
    {
        $allUserScores = self::getAllUserScores($roomId);
        $winners = array_filter($allUserScores, function($score) {
            return $score > 0;
        });
        $losers = array_filter($allUserScores, function($score) {
            return $score < 0;
        });

        $totalWinAmount = array_sum($winners);
        $totalLoseAmount = abs(array_sum($losers));

        if ($totalWinAmount != $totalLoseAmount) {
            return [
                'strategy' => 'error',
                'message' => '分数不平衡，无法生成结算策略',
                'transfers' => []
            ];
        }

        // 使用最优匹配算法生成结算策略
        $transfers = self::generateOptimalTransfers($winners, $losers);

        // 生成结算摘要
        $settlementSummary = [];
        foreach ($transfers as $transfer) {
            $key = $transfer['from_username'] . ' -> ' . $transfer['to_username'];
            if (!isset($settlementSummary[$key])) {
                $settlementSummary[$key] = 0;
            }
            $settlementSummary[$key] += $transfer['amount'];
        }

        $summaryText = [];
        foreach ($settlementSummary as $relation => $amount) {
            $summaryText[] = "{$relation}({$amount}分)";
        }
        $summary = implode('、', $summaryText);

        return [
            'strategy' => 'room_settlement',
            'message' => "房间净结算策略生成完成：{$summary}",
            'total_win_amount' => $totalWinAmount,
            'total_lose_amount' => $totalLoseAmount,
            'transfers' => $transfers,
            'summary' => $summary
        ];
    }

    /**
     * 生成最优结算策略
     * 优先保证大赢家获得足够分数，然后按比例分配
     */
    private static function generateOptimalTransfers($winners, $losers)
    {
        $transfers = [];
        
        // 按分数从高到低排序赢家（大赢家优先）
        arsort($winners);
        
        // 按分数从低到高排序输家（大输家优先）
        asort($losers);
        
        // 创建输家余额数组
        $loserBalances = [];
        foreach ($losers as $loserId => $loseAmount) {
            $loserBalances[$loserId] = abs($loseAmount);
        }
        
        // 为每个赢家分配结算
        foreach ($winners as $winnerId => $winAmount) {
            $remainingWinAmount = $winAmount;
            $winner = User::find($winnerId);
            
            // 从输家那里按优先级分配
            foreach ($losers as $loserId => $loseAmount) {
                if ($remainingWinAmount <= 0 || $loserBalances[$loserId] <= 0) {
                    continue;
                }
                
                // 计算这个输家应该给这个赢家多少钱
                $transferAmount = min($loserBalances[$loserId], $remainingWinAmount);
                
                if ($transferAmount > 0) {
                    $loser = User::find($loserId);
                    
                    $transfers[] = [
                        'from_user_id' => $loserId,
                        'from_username' => $loser ? $loser->nickname : '未知用户',
                        'to_user_id' => $winnerId,
                        'to_username' => $winner ? $winner->nickname : '未知用户',
                        'amount' => $transferAmount,
                        'description' => '最优净结算策略'
                    ];
                    
                    // 更新余额
                    $loserBalances[$loserId] -= $transferAmount;
                    $remainingWinAmount -= $transferAmount;
                }
            }
        }
        
        return $transfers;
    }

    /**
     * 生成考虑茶饭费的最优结算策略
     */
    public static function generateOptimalSettlementWithTeaMeal($roomId)
    {
        // 获取所有用户的分数（包括茶饭费）
        $allUserScores = self::getAllUserScores($roomId);
        
        // 分别获取分数记录和茶饭费记录
        $scoreRecords = AccountingRecord::where('room_id', $roomId)
            ->where('type', 'score')
            ->get()
            ->groupBy('user_id');
            
        $teaMealRecords = AccountingRecord::where('room_id', $roomId)
            ->where('type', 'tea_meal')
            ->get()
            ->groupBy('user_id');
        
        // 计算每个用户的净分数（分数 - 茶饭费）
        $netScores = [];
        foreach ($allUserScores as $userId => $score) {
            $teaMealAmount = $teaMealRecords->get($userId, collect())->sum('score');
            $netScores[$userId] = $score - $teaMealAmount;
        }
        
        $winners = array_filter($netScores, function($score) {
            return $score > 0;
        });
        $losers = array_filter($netScores, function($score) {
            return $score < 0;
        });

        $totalWinAmount = array_sum($winners);
        $totalLoseAmount = abs(array_sum($losers));

        if ($totalWinAmount != $totalLoseAmount) {
            return [
                'strategy' => 'error',
                'message' => '净分数不平衡，无法生成结算策略',
                'transfers' => []
            ];
        }

        // 使用最优匹配算法
        $transfers = self::generateOptimalTransfers($winners, $losers);

        // 生成结算摘要
        $settlementSummary = [];
        foreach ($transfers as $transfer) {
            $key = $transfer['from_username'] . ' -> ' . $transfer['to_username'];
            if (!isset($settlementSummary[$key])) {
                $settlementSummary[$key] = 0;
            }
            $settlementSummary[$key] += $transfer['amount'];
        }

        $summaryText = [];
        foreach ($settlementSummary as $relation => $amount) {
            $summaryText[] = "{$relation}({$amount}分)";
        }
        $summary = implode('、', $summaryText);

        return [
            'strategy' => 'optimal_settlement',
            'message' => "最优净结算策略（已扣除茶饭费）：{$summary}",
            'total_win_amount' => $totalWinAmount,
            'total_lose_amount' => $totalLoseAmount,
            'transfers' => $transfers,
            'summary' => $summary,
            'net_scores' => $netScores
        ];
    }
}
